<?php

namespace mbilling\BillingBundle\Services;

class JabberDirect implements JabberInterface
{
    protected $user;
    protected $domain;
    protected $password;
    protected $host;
    protected $port;
    protected $waiting_time;
    protected $stream;
    protected $securityContext;
    protected $session;
    
    public function __construct($securityContext, $session, $service_container)
    {
        $parameters = $service_container->getParameter('jabber');
        $this->user = $parameters['user']; // логин до '@'
        $this->domain = $parameters['domain']; // домен после '@'
        $this->password = $parameters['password']; // пароль
        $this->host = $parameters['host']; // jabber сервер
        $this->port = $parameters['port']; // порт
        $this->conference = $parameters['conference']; // конференция
        $this->waiting_time = $parameters['waiting_time']; //в секундах
        $this->securityContext = $securityContext;
        $this->session = $session;
    }

    public function connect()
    {
        // устанавливаем соединение с сервером
        $this->stream = fsockopen($this->host,$this->port,$errorno,$errorstr,10);
        stream_set_blocking($this->stream,0);
        stream_set_timeout($this->stream,3600*24);

        // после соединения с сервером посылаем приветствие
        $xml = '<?xml version="1.0"?>
        <stream:stream xmlns:stream="http://etherx.jabber.org/streams" version="1.0" xmlns="jabber:client" to="'.$this->domain.'" xml:lang="en" xmlns:xml="http://www.w3.org/XML/1998/namespace">';
        fwrite($this->stream,$xml."\n");
        $xmlin=$this->getxml($this->stream);
        // обрабатываем ответ сервера, узнаем может ли сервер работать в защищенном режиме,если может переходим в защищенный режим
        
        // посылаем команду на переход в защищенный режим
        $xml = '<starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>';
        fwrite($this->stream,$xml."\n");
        $xmlin=$this->getxml($this->stream);
        
        // если сервер подтвердил переводим поток в защищенный режим
        stream_set_blocking($this->stream, 1);
        stream_socket_enable_crypto($this->stream, TRUE, STREAM_CRYPTO_METHOD_TLS_CLIENT);
        stream_set_blocking($this->stream, 0);

        // после перехода в защищенный режим снова посылаем приветствие
        $xml = '<?xml version="1.0"?>';
        $xml .= '<stream:stream xmlns:stream="http://etherx.jabber.org/streams" version="1.0" xmlns="jabber:client" to="'.$this->domain.'" xml:lang="en" xmlns:xml="http://www.w3.org/XML/1998/namespace">';
        fwrite($this->stream, $xml."\n");
        $xmlin=$this->getxml($this->stream);
        
        // теперь проходим авторизацию
        $xml = '<auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="PLAIN">';
        $xml .= base64_encode("\x00".$this->user."\x00".$this->password); // вот так кодируется логин пароль для этого типа авторизации
        $xml .= '</auth>';
        fwrite($this->stream, $xml."\n");
        $xmlin=$this->getxml($this->stream);
        
        // после авторизации опять посылаем приветствие
        $xml = '<?xml version="1.0"?>';
        $xml .= '<stream:stream xmlns:stream="http://etherx.jabber.org/streams" version="1.0" xmlns="jabber:client" to="'.$this->domain.'" xml:lang="en" xmlns:xml="http://www.w3.org/XML/1998/namespace">';
        fwrite($this->stream,$xml."\n");
        $xmlin=$this->getxml($this->stream);
        
        // сейчас устанавливаем имя ресурса (расположение вашего клиента)
        $xml = '<iq type="set" id="2"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><resource>webi</resource></bind></iq>';
        fwrite($this->stream,$xml."\n");
        $xmlin=$this->getxml($this->stream);
        
        // пошла сессия
        $xml = '<iq type="set" id="sess_2" to="'.$this->domain.'"><session xmlns="urn:ietf:params:xml:ns:xmpp-session"/></iq>';
        fwrite($this->stream,$xml."\n");
        $xmlin=$this->getxml($this->stream);
        
        // а теперь можно получить список контактов
        $xml = '<iq type="get" id="3"><query xmlns="jabber:iq:roster"/></iq>';
        fwrite($this->stream,$xml."\n");
        $xmlin=$this->getxml($this->stream); // здесь сейчас список контактов
        
        // ну и теперь выходим в онлайн и становимся видимыми для контактов
        $xml = '<presence><show></show><status>мой статус онлайн</status><priority>10</priority></presence>';
        fwrite($this->stream,$xml."\n");
        $xmlin=$this->getxml($this->stream); // после выхода в онлайн здесь будут получены офлайн сообщения и дополнительная информация по статусам ваших контактов.
        $this->getMessage($this->parse($xmlin));

        //вход в конференцию
        //$xml = '<presence to="'.$this->conference.'/'.$this->user.'@'.$this->domain.'">
        $xml = '<presence to="'.$this->conference.'/'.$this->user.'">
        <x xmlns="http://jabber.org/protocol/muc"/></presence>';
        fwrite($this->stream,$xml."\n");
        $xmlin=$this->getxml($this->stream);

        //отправка сообщения
        //$params['prefix'] = 'r';
        //$this->sendMessage(9, $params);
    }

    public function waitMessage($message_id)//$num_messages = 1)
    {
        $time = time();
        $end = $time + $this->waiting_time;
        //$current_message = 0;
        $output = array();
        while($time < $end)//пока не пройдет waiting_time секунд или пока не будет получено нужное количество ответов
        {
            //if ($current_message >= $num_messages)
               // break;
            
            $time = time();
            sleep(1);
            $xmlin=$this->getxml(); //тут будут приходить сообщения, информация о смене статусов ваших контактов и т.д.
            //echo $xmlin;
            $result = $this->getMessage($this->parse($xmlin));
            //print_r($result);
            if (isset($result['0']['0']))
                return $result;
            /*if ($result = $this->getMessage($this->parse($xmlin)))
            {
                //array_pop($result);
                //$output[$current_message] = $result;
                //$current_message += 1;
                //return $result;
            }*/
        }
        return $result;
    }
    
    public function sendMessage($action, $params = array())
    {
        //1 - создать новый виртуальнй диск
        //2 - активировать виртуальный диск
        //3 - деактивировать виртуальный диск
        //4 - получить видимые AoE exports для виртуального диска
        //5 - информация о доступном месте на hdd
        //6 - информация о доступном памяти
        //7 - проверка состояния виртуального диска
        //8 - проверка состояния виртуального сервера
        //9 - получить список mysql пользователей
        //10- создать нового mysql пользователя
        //11- получить список баз данных
        //12- создать новую базу данных
        //13- получить список пользователей имеющих права на базу
        //14- получить список прав пользователей на базу
        //15- удаление mysql пользователя
        //16- создание unix пользователя и его домашней директории
        //17- удаление unix пользователя
        //18- удаление базы данных
        
        switch ($action)
        {
            case 1:
                $message = '<fipa-message ontology="cirrocumulus-xen" act="request"><content>(create (raid (disk_number '.$disk_number.') (size '.$size.')))</content></fipa-message>';
            break;
            case 2:
                $message = '<fipa-message ontology="cirrocumulus-xen" act="request"><content>(start (raid '.$disk_number.'))</content></fipa-message>';
            break;
            case 3:
                $message = '<fipa-message ontology="cirrocumulus-xen" act="request"><content>(stop (raid '.$disk_number.'))</content></fipa-message>';
            break;
            case 4:
                $message = '<fipa-message ontology="cirrocumulus-xen" act="query-ref"><content>(state (aoe '.$disk_number.'))</content></fipa-message>';
            break;
            case 5:
                $message = '<fipa-message ontology="cirrocumulus-storage" act="query-ref"><content>(free_space)</content></fipa-message>';
            break;
            case 6:
                $message = '<fipa-message ontology="cirrocumulus-xen" act="query-ref"><content>(free_memory)</content></fipa-message>';
            break;
            case 7:
                $message = '<fipa-message ontology="cirrocumulus-xen" act="query-ref"><content>(state (raid '.$disk_number.'))</content></fipa-message>';
            break;
            case 8:
                $message = '<fipa-message ontology="cirrocumulus-xen" act="query-if"><content>(running (domu "DOMU_NAME"))</content></fipa-message>';
            break;
            case 9:
                $message = '<fipa-message ontology="vh-master" act="query-ref"><content>(show (mysql_user '.$params['prefix'].'))</content></fipa-message>';
            break;
            case 10:
                $message = '<fipa-message ontology="vh-master" act="request"><content>(create (mysql_user '.$params['name'].' '.$params['login'].' '.$params['password'].'))</content></fipa-message>';
            break;
            case 11:
                $message = '<fipa-message ontology="vh-master" act="query-ref"><content>(show (database '.$params['prefix'].'))</content></fipa-message>';
            break;
            case 12:
                $message = '<fipa-message ontology="vh-master" act="request"><content>(create (database '.$params['name'].' '.$params['login'].' '.$params['password'].'))</content></fipa-message>';
            break;
            case 13:
                $message = '<fipa-message ontology="vh-master" act="query-ref"><content>(show (database_user '.$params['prefix'].'))</content></fipa-message>';
            break;
            case 14:
                $message = '<fipa-message ontology="vh-master" act="query-ref"><content>(show (database_privelege '.$params['prefix'].'))</content></fipa-message>';
            break;
            case 15:
                $message = '<fipa-message ontology="vh-master" act="request"><content>(drop (mysql_user '.$params['login'].'))</content></fipa-message>';
            break;
            case 16:
                $message = '<fipa-message ontology="vh-master" act="request"><content>(create (unix_user '.$params['password'].'))</content></fipa-message>';
            break;
            case 17:
                $message = '<fipa-message ontology="vh-master" act="request"><content>(drop (unix_user '.$params['login'].'))</content></fipa-message>';
            break;
            case 18:
                $message = '<fipa-message ontology="vh-master" act="request"><content>(drop (database '.$params['name'].'))</content></fipa-message>';
            break;
            default:
                $message = '';
            break;
        //<fipa-message ontology="cirrocumulus-vh" act="query-database"><content>(show (mysql_users test))</content></fipa-message> 
        //<fipa-message ontology="cirrocumulus-vh" act="request"><content>(run (script script2.sh))</content></fipa-message>
        }
        $message = htmlentities($message, ENT_QUOTES, 'utf-8');
        $xml = '<message type="groupchat" from="'.$this->user.'@'.$this->domain.'" to="'.$this->conference.'" id="et5r">';
        $xml .= '<body>'.$message.'</body>';
        $xml .= '</message>';
        fwrite($this->stream,$xml."\n");
        return 0;
    }
    
    public function getMessage($xml_ob)
    {
        if (isset($xml_ob->message)) // если есть сообщения
        {
            $has_body = false;
            //print_r($xml_ob);
            $result = array();
            foreach ($xml_ob->message as $message)
            {
                //print_r($message);
                if (isset($message->body))// чтобы не срабатывало на сообщение "оповещение о наборе" и все подобное
                {
                    //print_r($message);
                    //$message->body = htmlentities($message->body, ENT_QUOTES, 'utf-8');
                    $message = (array)$message;
                    if ($message['@attributes']['from'] != $this->conference.'/'.$this->user)
                    {
                        $has_body = true;
                        $message['body'] = preg_replace("/<fipa(.)*<content>/", '', $message['body']);
                        $message['body'] = preg_replace("/\(=(.)*\) \(/", '', $message['body']);
                        $message['body'] = preg_replace("/(\))*\"/", '', $message['body']);
                        $message['body'] = preg_replace("/<\/content>(.)*-message>/", '', $message['body']);

                        //print_r($message);
                        $res = explode("\n", $message['body']);
                        array_pop($res);
                        //print_r($result);
                        //$result[$key] = $res;
                        array_push($result, $res);
                        //print_r($res);
                        /*
                        echo $message->body; // очередное сообщение
                        echo "<br>";
                        echo $message->attributes()->from; // от кого сообщение
                        echo "<br>";
                        echo "<br>";*/
                        //print_r($message);
                    }
                }
            }
            return $result;
            /*if ($has_body)
                return true;
            else
                return false;*/
        }
        else
            return false;
    }
    public function parse($xmlin)
    {
        $xmlin = preg_replace ("'<\?xml.*\?>'si", "", $xmlin); // сначала удалим начальный тег < xml > если он есть
        $xmlin = "<webi_xml>".$xmlin."</webi_xml>"; // окружение xml специфическим тегом, чтобы получилась обработка некоторых невалидных xml
        $xml_ob=simplexml_load_string($xmlin);
        //if (isset($xml_ob->message->body))
            //$xml_ob->message->body = htmlentities($xml_ob->message->body, ENT_QUOTES, 'utf-8');
        //print_r($xml_ob);
        return $xml_ob;
    }
    public function getxml()
    {
        sleep(1); // перед получением информации дадим паузу, чтобы сервер успел отдать информацию
        $xml='';
        // запрашивать данные 1600 раз, но не более 15 пустых строк
        $emptyLine = 0;
        for($i=0; $i<1600; $i++)
        {
            $line = fread($this->stream,2048);
            if(strlen($line) == 0)
            {
                $emptyLine++;
                if($emptyLine > 15) break;
            }
            else
            {
                $xml .= $line;
            }
        }
        if(!$xml) return false;
        return $xml;
    }
    
}
